我們要上雲之前,還是需要串接模型而後進行下單。因此有請我們上次的程式碼:
from shioaji import TickSTKv1, Exchange, Shioaji, constant, BidAskSTKv1
from threading import Event # event模組用於維持程式運作
api = Shioaji()
accounts = api.login(api_key="",
secret_key=""
)
#訂閱個股盤中tick資訊
api.quote.subscribe(
api.Contracts.Stocks["2330"],
quote_type = constant.QuoteType.Tick,
version = constant.QuoteVersion.v1
)
# 維持程式運作等待交易資料送入
Event().wait()
# 定義quote_callback,即回傳報價資訊時所要執行的動作
@api.on_tick_stk_v1()
def quote_callback(exchange: Exchange, tick:TickSTKv1):
print(f"Exchange: {exchange}, Tick: {tick}") #將報價資訊內容輸出
api.logout()
這一個程式碼會訂閱股票代號 2330 的股票,並且秀出報價資料。
但是我們目前的策略如下:
因此我們的設計只需要取得昨天算出來可以交易的股票,並且在程式運作時維持監控停損即可。以下是需要的幾個API:
下單前要有憑證,在永豐官網那邊可以取得,今天先不要使用,避免胡亂下單。
result = api.activate_ca(
ca_path=os.getenv('YOUR_CA_PATH'), # 下單電子憑證路徑及檔案名稱
ca_passwd=os.getenv('YOUR_CA_PASS'), # 下單電子憑證密碼
person_id=os.getenv('YOUR_PERSON_ID'), # 身份證字號
)
下委託單前要先建立order物件,詳細的參數請前看兩天前的那一篇:
order = api.Order(price=,
quantity=,
action=,
price_type=,
order_type=,
order_cond=,
order_lot=,
first_sell=,
account=
)
委託建立之後要發送出去:
api.place_order(
contract: Contract,
order: Order,
timeout: int = 5000
)
定時查詢及時庫存,以進行監控停損停利。
api.list_positions(
account: shioaji.account.Account = None, #交易帳戶,預設為None
unit: shioaji.constant.Unit = <Unit.Common: 'Common'>, #單位,預設為整股
timeout: int = 5000 #timeout預設為5000ms,即延遲時間?
)
我們整理一下需要的業務邏輯,我們會需要幾個物件去管理業務邏輯:
其實還會需要:
一開始我們先假設已經取得要下單的股票代號列表,先讓程式可以開盤買進:
from shioaji import TickSTKv1, Exchange, Shioaji, constant, BidAskSTKv1
from threading import Event # event模組用於維持程式運作
from datetime import datetime
stock_list = ['2330']
api = Shioaji(simulation=True)
accounts = api.login(api_key="",
secret_key="",
)
def open_market_buy(stock_list):
'''
開盤買進,理論上程式會在開盤前就執行,因此我們在開盤前預掛委託單,
'''
if time_chack(): # 確定時間是否在開盤之前
for stock_id in stock_list:
# 製作委託單
order = api.Order(price=api.Contracts.Stocks[stock_id].limit_up,
quantity=1,
action='Buy',
price_type='LMT', # 限價單
order_type='ROD',
order_cond='Cash',
order_lot='Common', # 整股
first_sell='false',
account=accounts[0]
)
# 發送委託單
api.place_order(
contract=api.Contracts.Stocks[stock_id],
order=order,
timeout=5000
)
print(stock_id)
else:
print('開盤後')
pass
def time_chack():
'''
確定時間是否在開盤之前
'''
# 獲取當前時間
now = datetime.now()
# 獲取當前的時和分
current_hour = now.hour
current_minute = now.minute
# 如果啟動時已經開盤了就不做交易,如果還沒有開盤就執行交易。
if current_hour < 9 or (current_hour == 9 and current_minute == 0):
return True
else:
return False
open_market_buy(stock_list=stock_list)
# 維持程式運作等待交易資料送入
Event().wait()
# 定義quote_callback,即回傳報價資訊時所要執行的動作
@api.on_tick_stk_v1()
def quote_callback(exchange: Exchange, tick:TickSTKv1):
print(f"Exchange: {exchange}, Tick: {tick}") #將報價資訊內容輸出
api.logout()
上面的程式碼我們先用這部分去完成時間的檢驗,如果已經開盤了我們就不交易了,如果沒有開盤我們才預掛委託單。
def time_chack():
'''
確定時間是否在開盤之前
'''
# 獲取當前時間
now = datetime.now()
# 獲取當前的時和分
current_hour = now.hour
current_minute = now.minute
# 如果啟動時已經開盤了就不做交易,如果還沒有開盤就執行交易。
if current_hour < 9 or (current_hour == 9 and current_minute == 0):
return True
else:
return False
接著我們再用以下方法處理交易的部分,這裡要注意開盤前是不能掛市價單的,所以我們就掛漲停限價單。
def open_market_buy(stock_list):
'''
開盤買進,理論上程式會在開盤前就執行,因此我們在開盤前預掛委託單,
'''
if time_chack(): # 確定時間是否在開盤之前
for stock_id in stock_list:
# 製作委託單
order = api.Order(price=api.Contracts.Stocks[stock_id].limit_up,
quantity=1,
action='Buy',
price_type='LMT', # 限價單
order_type='ROD',
order_cond='Cash',
order_lot='Common', # 整股
first_sell='false',
account=accounts[0]
)
# 發送委託單
api.place_order(
contract=api.Contracts.Stocks[stock_id],
order=order,
timeout=5000
)
print(stock_id)
else:
print('開盤後')
pass
接下來實作監控停損
我們把判斷式寫再cellback函式中,並且訂閱相關需要的股票代號。
from shioaji import TickSTKv1, Exchange, Shioaji, constant, BidAskSTKv1
from threading import Event # event模組用於維持程式運作
from datetime import datetime
stock_list = ['2330']
sell_price = {'2330': {
'high':400,
'low':100
}
}
api = Shioaji(simulation=True)
accounts = api.login(api_key="",
secret_key="",
)
def open_market_buy(stock_list):
'''
開盤買進,理論上程式會在開盤前就執行,因此我們在開盤前預掛委託單,
'''
if time_chack(): # 確定時間是否在開盤之前
for stock_id in stock_list:
# 製作委託單
order = api.Order(price=api.Contracts.Stocks[stock_id].limit_up,
quantity=1,
action='Buy',
price_type='LMT', # 限價單
order_type='ROD',
order_cond='Cash',
order_lot='Common', # 整股
first_sell='false',
account=accounts[0]
)
# 發送委託單
api.place_order(
contract=api.Contracts.Stocks[stock_id],
order=order,
timeout=5000
)
#為了監控買進的標的是否需要停損,所以訂閱tick資訊
api.quote.subscribe(
api.Contracts.Stocks[stock_id],
quote_type = constant.QuoteType.Tick,
version = constant.QuoteVersion.v1
)
print(stock_id)
else:
print('開盤後')
pass
def time_chack():
'''
確定時間是否在開盤之前
'''
# 獲取當前時間
now = datetime.now()
# 獲取當前的時和分
current_hour = now.hour
current_minute = now.minute
# 如果啟動時已經開盤了就不做交易,如果還沒有開盤就執行交易。
if current_hour < 9 or (current_hour == 9 and current_minute == 0):
return True
else:
return False
open_market_buy(stock_list=stock_list)
# 為了要能夠監控盤中的個股狀況,我們需要訂閱需要監控的個股
for stock_id in stock_list:
#訂閱個股盤中tick資訊
api.quote.subscribe(
api.Contracts.Stocks[stock_id],
quote_type = constant.QuoteType.Tick,
version = constant.QuoteVersion.v1
)
# 維持程式運作等待交易資料送入
Event().wait()
# 定義quote_callback,即回傳報價資訊時所要執行的動作
@api.on_tick_stk_v1()
def quote_callback(exchange: Exchange, tick:TickSTKv1):
print(f"Exchange: {exchange}, Tick: {tick}") #將報價資訊內容輸出
# 停利
if tick.close >= sell_price[tick.code]['high']:
# 製作委託單
order = api.Order(price=api.Contracts.Stocks[tick.code].limit_down,
quantity=1,
action='Sell',
price_type='LMT', # 限價單
order_type='ROD',
order_cond='Cash',
order_lot='Common', # 整股
first_sell='false',
account=accounts[0]
)
# 發送委託單
api.place_order(
contract=api.Contracts.Stocks[tick.code],
order=order,
timeout=5000
)
# 停損
elif tick.close <= sell_price[tick.code]['low']:
# 製作委託單
order = api.Order(price=api.Contracts.Stocks[stock_id].limit_down,
quantity=1,
action='Sell',
price_type='LMT', # 限價單
order_type='ROD',
order_cond='Cash',
order_lot='Common', # 整股
first_sell='false',
account=accounts[0]
)
# 發送委託單
api.place_order(
contract=api.Contracts.Stocks[stock_id],
order=order,
timeout=5000
)
else:
pass
api.logout()
將程式碼封裝到函數中,提高易讀性以及可維護性。
from shioaji import TickSTKv1, Exchange, Shioaji, constant, BidAskSTKv1
from threading import Event
from datetime import datetime
def init_api():
"""初始化API"""
return Shioaji(simulation=True)
def login(api, api_key, secret_key):
"""登入API"""
return api.login(api_key=api_key, secret_key=secret_key)
def is_market_open():
"""檢查市場是否開放"""
now = datetime.now()
return 9 <= now.hour < 15
def place_order(api, stock_id, action, price, accounts):
"""下單"""
order = api.Order(
price=price,
quantity=1,
action=action,
price_type='LMT', # 限價單
order_type='ROD', # 僅今日有效
order_cond='Cash', # 現股交易
order_lot='Common', # 整股
first_sell='false',
account=accounts[0]
)
api.place_order(
contract=api.Contracts.Stocks[stock_id],
order=order,
timeout=5000
)
def subscribe_stock(api, stock_id):
"""訂閱股票報價"""
api.quote.subscribe(
api.Contracts.Stocks[stock_id],
quote_type=constant.QuoteType.Tick,
version=constant.QuoteVersion.v1
)
def quote_callback(exchange: Exchange, tick: TickSTKv1):
"""報價回調函數"""
print(f"Exchange: {exchange}, Tick: {tick}")
if tick.close >= sell_price[tick.code]['high']:
place_order(api, tick.code, 'Sell', api.Contracts.Stocks[tick.code].limit_down, accounts)
elif tick.close <= sell_price[tick.code]['low']:
place_order(api, tick.code, 'Sell', api.Contracts.Stocks[tick.code].limit_down, accounts)
if __name__ == "__main__":
stock_list = ['2330']
sell_price = {'2330': {'high': 400, 'low': 100}}
api = init_api()
accounts = login(api, "9EwVF2HtBmfeexfLBYUExWvFbaL6f1jenPfxESjSo4x5", "5BW5ZxGc3Vz186y5EzhCeg7b25qC3bD2kk823t9L7kyx")
if not is_market_open():
for stock_id in stock_list:
place_order(api, stock_id, 'Buy', api.Contracts.Stocks[stock_id].limit_up, accounts) # 預掛開盤買進的委託單
subscribe_stock(api, stock_id) # 訂閱開盤買進的個股
else:
print("市場已經開盤。")
for stock_id in stock_list:
subscribe_stock(api, stock_id) # 訂閱盤中需要監控的個股
api.on_tick_stk_v1(quote_callback)
api.on_tick_stk_v1(quote_callback) # 設定報價回調函數
Event().wait() # 維持程式運作,等待交易資料送入
api.logout() # 登出API